import { edpService } from 'edpdeck/src/decorators';
import express from 'express';
import plotly from 'plotly.js-dist-min';
import path from 'path';
import { exec } from 'child_process';
import fs from 'fs';
let serial_id = 0;

@edpService
class VisualizeService {
    static serviceName = 'ts-visualizer';
    static desc = 'EDP Visualization Service in Typescript';
    static category = 'visualization';
    static tasks = [
        '#instant pose_vis: List<(PoseFlat, Confidence)>->Void',
        '#instant pose_vis_then: List<(PoseFlat, Confidence)>->List<(PoseFlat, Confidence)>',
        '#instant pose_single_stim: (List<(PoseFlat, Confidence)>, (Int, Int, Frequency))->Void',
        '#instant feature_model_vis: ([[[PoseStim]]], Str)->Void',
        '#instant feature_model_vis_move: ([[[PoseStim]]], Str)->Void',
        '#instant feature_model_vis_30Hz: ([[[PoseStim]]], Str)->Void',
        '#instant from_feat3_file: FilePath->([[[PoseStim]]], Str)'
    ];
    static app: express.Express;
    static port = 3010;
    pose_vis(inputs: [[number, number, number], number][]) {
        const poses = inputs.map(([pose, confidence]) => pose);
        const timestamps = Array.from({length: inputs.length}, (_, i) => i);
        const trajectoryTrace = {
            x: poses.map(p => p[0]),
            y: poses.map(p => p[1]),
            type: 'scatter',
            mode: 'lines+markers',
            name: '轨迹',
            line: {
                color: poses.map((_, i) => {
                    const t = i / (poses.length - 1);
                    return `hsl(${t * 300}, 100%, 50%)`;
                }),
                width: 2
            },
            marker: {
                size: 6,
                color: poses.map((_, i) => {
                    const t = i / (poses.length - 1);
                    return `hsl(${t * 300}, 100%, 50%)`;
                })
            }
        };
        const angleTrace = {
            x: timestamps,
            y: poses.map(p => p[2]),
            type: 'scatter',
            mode: 'lines',
            name: '角度变化',
            line: {
                color: 'green',
                width: 2
            }
        };
        const trajectoryLayout = {
            title: '半机械昆虫运动轨迹',
            xaxis: {
                title: 'X坐标',
                showgrid: true
            },
            yaxis: {
                title: 'Y坐标',
                showgrid: true
            },
            showlegend: true
        };

        const angleLayout = {
            title: '角度随时间变化',
            xaxis: {
                title: '时间步',
                showgrid: true
            },
            yaxis: {
                title: '角度 (弧度)',
                showgrid: true
            },
            showlegend: true
        };
        const staticDir = path.join(__dirname, 'public');
        VisualizeService.app?.use(express.static(staticDir));
        serial_id++;
        VisualizeService.app?.get(`/visualize/${serial_id}`, (req, res) => {
            const html = `
                <!DOCTYPE html>
                <html>
                <head>
                    <title>位姿可视化</title>
                    <script src="https://cdn.bootcdn.net/ajax/libs/plotly.js/3.0.1/plotly-basic.min.js"></script>
                    <style>
                        .plot-container {
                            display: flex;
                            justify-content: space-between;
                            padding: 20px;
                        }
                        .plot {
                            width: 48%;
                            height: 500px;
                        }
                    </style>
                </head>
                <body>
                    <div class="plot-container">
                        <div id="trajectory" class="plot"></div>
                        <div id="angle" class="plot"></div>
                    </div>
                    <script>
                        const trajectoryData = ${JSON.stringify([trajectoryTrace])};
                        const trajectoryLayout = ${JSON.stringify(trajectoryLayout)};
                        Plotly.newPlot('trajectory', trajectoryData, trajectoryLayout);

                        const angleData = ${JSON.stringify([angleTrace])};
                        const angleLayout = ${JSON.stringify(angleLayout)};
                        Plotly.newPlot('angle', angleData, angleLayout);
                    </script>
                </body>
                </html>
            `;
            res.send(html);
        });
        const url = `http://localhost:${VisualizeService.port}/visualize/${serial_id}`;
        const command = process.platform === 'win32' 
            ? `start ${url}`  // Windows
            : process.platform === 'darwin'
                ? `open ${url}`  // macOS
                : `xdg-open ${url}`;  // Linux
        exec(command, (error) => {
            if (error) {
                console.error('Failed to open browser:', error);
            }
        });
        return null;
    }
    pose_single_stim(inputs: [[[number, number, number], number][], [number, number, number]]) {
        const poses = inputs[0];
        const [start, end, frequency] = inputs[1];
        // filter poses by start and end
        const filteredPoses: [[number, number, number], number][] = [];
        for (let i = start; i <= end; i++) {
            filteredPoses.push(poses[i]);
        }
        return this.pose_vis(filteredPoses);
    }
    pose_vis_then(inputs: [[number, number, number], number][]) {
        this.pose_vis(inputs);
        return inputs;
    }
    from_feat3_file(inputs: string): [[number, number, number, number, number][][][], string] {
        const data = JSON.parse(fs.readFileSync(inputs, 'utf8'));
        const modelid = data['model'];
        let res = [];
        const dataTypes = ['static_left', 'static_right', 'move_left', 'move_right'];
        for (let dt of dataTypes) {
            res.push(data[dt + 's']);
        }
        return [res, modelid];
    }
    from_old_feat3_file(inputs: string): [[number, number, number, number, number][][][], string] {
        const data = JSON.parse(fs.readFileSync(inputs, 'utf8'));
        const modelid = path.basename(inputs, '.json');
        let res = [];
        const dataTypes = ['static_left', 'static_right', 'move_left', 'move_right'];
        for (let dt of dataTypes) {
            let temp: [number, number, number, number, number][][] = [];
            for (let i = 0; i < 6; i++) {
                if (i == 2) {
                    temp.push(data[dt]);
                } else {
                    temp.push([[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]);
                }
            }
            res.push(temp);
        }
        return [res, modelid];
    }
    feature_model_vis(inputs: [[number, number, number, number, number][][][], string]) {
        const modelId = inputs[1];
        const data = inputs[0];
        const dataTypes = ['static_left', 'static_right', 'move_left', 'move_right'];
        const colors = ['#FF9999', '#66B2FF', '#99FF99', '#FFCC99'];

        interface DataPoint {
            x: number;
            y: number;
            type: string;
            time: number;
        }

        interface AnglePoint {
            angle: number;
            type: string;
            time: number;
        }

        // 准备轨迹数据
        const trajectoryData: DataPoint[] = [];
        for (let i = 0; i < data.length; i++) {
            const currentData = data[i][2];
            if (currentData && currentData.length > 0) {
                for (let j = 0; j < currentData.length; j++) {
                    trajectoryData.push({
                        x: currentData[j][0],
                        y: currentData[j][1],
                        type: dataTypes[i],
                        time: j
                    });
                }
            }
        }

        // 准备角度数据
        const angleData: AnglePoint[] = [];
        for (let i = 0; i < data.length; i++) {
            const currentData = data[i][2];
            if (currentData && currentData.length > 0) {
                for (let j = 0; j < currentData.length; j++) {
                    angleData.push({
                        angle: currentData[j][2],
                        type: dataTypes[i],
                        time: j
                    });
                }
            }
        }

        // 创建轨迹图
        const trajectoryTraces = dataTypes.map((type, i) => {
            const filteredData = trajectoryData.filter(d => d.type === type);
            return {
                x: filteredData.map(d => d.x),
                y: filteredData.map(d => d.y),
                type: 'scatter',
                mode: 'lines+markers',
                name: type,
                line: {
                    color: colors[i],
                    width: 2
                },
                marker: {
                    size: 8,
                    color: colors[i]
                }
            };
        });

        // 创建角度图
        const angleTraces = dataTypes.map((type, i) => {
            const filteredData = angleData.filter(d => d.type === type);
            return {
                x: filteredData.map(d => d.time),
                y: filteredData.map(d => d.angle),
                type: 'scatter',
                mode: 'lines+markers',
                name: type,
                line: {
                    color: colors[i],
                    width: 2
                },
                marker: {
                    size: 8,
                    color: colors[i]
                }
            };
        });

        const trajectoryLayout = {
            title: '轨迹预测',
            xaxis: {
                title: {
                    text: 'X坐标 (mm)',
                    font: {
                        size: 21
                    }
                },
                showgrid: true,
                tickfont: {
                    size: 18
                }
            },
            yaxis: {
                title: {
                    text: 'Y坐标 (mm)',
                    font: {
                        size: 21
                    }
                },
                showgrid: true,
                tickfont: {
                    size: 18
                }
            },
            showlegend: true,
            legend: {
                font: {
                    size: 21
                }
            }
        };

        const angleLayout = {
            title: '角度预测',
            xaxis: {
                title: {
                    text: '时间 (s)',
                    font: {
                        size: 21
                    }
                },
                showgrid: true,
                tickfont: {
                    size: 18
                }
            },
            yaxis: {
                title: {
                    text: '角度 (°)',
                    font: {
                        size: 21
                    }
                },
                showgrid: true,
                tickfont: {
                    size: 18
                }
            },
            showlegend: true,
            legend: {
                font: {
                    size: 21
                }
            }
        };

        const staticDir = path.join(__dirname, 'public');
        VisualizeService.app?.use(express.static(staticDir));
        serial_id++;
        VisualizeService.app?.get(`/visualize/${serial_id}`, (req, res) => {
            const html = `
                <!DOCTYPE html>
                <html>
                <head>
                    <title>${modelId}特征模型可视化</title>
                    <script src="https://cdn.bootcdn.net/ajax/libs/plotly.js/3.0.1/plotly-basic.min.js"></script>
                    <style>
                        .container {
                            padding: 20px;
                            max-width: 1200px;
                            margin: 0 auto;
                        }
                        .title {
                            text-align: center;
                            font-size: 36px;
                            margin-bottom: 20px;
                            font-weight: bold;
                        }
                        .plot-container {
                            display: flex;
                            flex-direction: column;
                            gap: 20px;
                        }
                        .plot {
                            width: 100%;
                            height: 600px;
                        }
                    </style>
                </head>
                <body>
                    <div class="container">
                        <div class="title">${modelId}特征模型可视化</div>
                        <div class="plot-container">
                            <div id="trajectory" class="plot"></div>
                            <div id="angle" class="plot"></div>
                        </div>
                    </div>
                    <script>
                        const trajectoryData = ${JSON.stringify(trajectoryTraces)};
                        const trajectoryLayout = ${JSON.stringify({
                            ...trajectoryLayout,
                            title: {
                                text: '轨迹预测',
                                font: {
                                    size: 30
                                }
                            },
                            xaxis: {
                                title: {
                                    text: 'X坐标 (mm)',
                                    font: {
                                        size: 21
                                    }
                                },
                                showgrid: true,
                                tickfont: {
                                    size: 18
                                }
                            },
                            yaxis: {
                                title: {
                                    text: 'Y坐标 (mm)',
                                    font: {
                                        size: 21
                                    }
                                },
                                showgrid: true,
                                tickfont: {
                                    size: 18
                                }
                            },
                            legend: {
                                font: {
                                    size: 21
                                }
                            }
                        })};
                        Plotly.newPlot('trajectory', trajectoryData, trajectoryLayout);

                        const angleData = ${JSON.stringify(angleTraces)};
                        const angleLayout = ${JSON.stringify({
                            ...angleLayout,
                            title: {
                                text: '角度预测',
                                font: {
                                    size: 30
                                }
                            },
                            xaxis: {
                                title: {
                                    text: '时间 (s)',
                                    font: {
                                        size: 21
                                    }
                                },
                                showgrid: true,
                                tickfont: {
                                    size: 18
                                }
                            },
                            yaxis: {
                                title: {
                                    text: '角度 (°)',
                                    font: {
                                        size: 21
                                    }
                                },
                                showgrid: true,
                                tickfont: {
                                    size: 18
                                }
                            },
                            legend: {
                                font: {
                                    size: 21
                                }
                            }
                        })};
                        Plotly.newPlot('angle', angleData, angleLayout);
                    </script>
                </body>
                </html>
            `;
            res.send(html);
        });

        const url = `http://localhost:${VisualizeService.port}/visualize/${serial_id}`;
        const command = process.platform === 'win32' 
            ? `start ${url}`  // Windows
            : process.platform === 'darwin'
                ? `open ${url}`  // macOS
                : `xdg-open ${url}`;  // Linux
        exec(command, (error) => {
            if (error) {
                console.error('Failed to open browser:', error);
            }
        });

        return null;
    }
}

const file_path = "C:/Users/songy/Desktop/data-0518/feat3/old-0518164729-best_4231.json"
let service = new VisualizeService()
service.feature_model_vis(service.from_old_feat3_file(file_path))
VisualizeService.app?.listen(VisualizeService.port, () => {
    console.log(`Visualization service is running on port ${VisualizeService.port}`);
}); 